/*
 * Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "cmsis_os2.h"
#include "ohos_init.h"

#include "wifi_device.h"
#include "wifi_hotspot.h"
#include "wifi_error_code.h"
#include "lwip/netifapi.h"
#include "kv_store.h"

//定义AP模式的wifi名称和密码
#define AP_SSID "My_WIFI"
#define AP_PSK  "12345678"

#define TASK_STACK_SIZE (1024 * 10)
#define TASK_PRIO 25
#define TASK_DELAY_2S 200
#define ONE_SECOND 1
#define DEF_TIMEOUT 15
#define CHANNEL_NUM 7
#define MAC_ADDRESS_LEN 32
#define MAC_DATA0 0
#define MAC_DATA1 1
#define MAC_DATA2 2
#define MAC_DATA3 3
#define MAC_DATA4 4
#define MAC_DATA5 5
#define UDP_SERVERPORT 3456

static void OnHotspotStaJoinHandler(StationInfo *info);
static void OnHotspotStateChangedHandler(int state);
static void OnHotspotStaLeaveHandler(StationInfo *info);

static struct netif *g_lwip_netif = NULL;
static int g_apEnableSuccess = 0;
static WifiEvent g_wifiEventHandler = { 0 };
static WifiErrorCode error;

//定义kv存储的ssid和pwd的key
#define KV_SSID "ssid"
#define KV_PWD "password"
/*
保存wifi的ssid和密码
***/
static void saveWifiInfo(char *ssid, char *pwd){
    if (UtilsSetValue(KV_SSID, ssid) !=0){
        printf("store ssid failed! \n");
        return;
    }
    if (UtilsSetValue(KV_PWD, pwd) != 0){
        printf("store password failed! \n");
        return;
    }
    printf("store password success! \n");
}

/****************以下为UDP服务器代码,默认IP:192.168.5.1***************/
static int StartUdpServer(void)
{
    
    // 在sock_fd 进行监听
    int sock_fd;
    // 服务端地址信息
    struct sockaddr_in server_sock;

    // 创建socket
    if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("socket is error.\r\n");
        return -1;
    }

    bzero(&server_sock, sizeof(server_sock));
    server_sock.sin_family = AF_INET;
    server_sock.sin_addr.s_addr = htonl(INADDR_ANY);
    server_sock.sin_port = htons(UDP_SERVERPORT);

    // 调用bind函数绑定socket和地址
    if (bind(sock_fd, (struct sockaddr *)&server_sock, sizeof(struct sockaddr)) == -1) {
        perror("bind is error.\r\n");
        return -1;
    }
    
    int ret;
    char recvBuf[512] = { 0 };
    char sendBuf[512] = { 0 };
    int index = 0;
    // 客户端地址信息
    struct sockaddr_in client_addr;
    int size_client_addr = sizeof(struct sockaddr_in);
    /*
    ssid:xxx,pwd:xxx
    */
    while (1) {
        printf("Waiting to receive data...\r\n");
        memset_s(recvBuf, sizeof(recvBuf), 0, sizeof(recvBuf));
        ret = recvfrom(sock_fd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr*)&client_addr,
            (socklen_t*)&size_client_addr);
        if (ret < 0) {
            printf("UDP server receive failed!\r\n");
            return -1;
        }
        printf("receive %d bytes of data from ipaddr = %s, port = %d.\r\n", ret, inet_ntoa(client_addr.sin_addr),
            ntohs(client_addr.sin_port));
        printf("data is %s\r\n", recvBuf);

        /**
        *解析收到的数据,格式:ssid:xxxx,pwd:yyyy
        */
        char *ssid_str = strstr(recvBuf,"ssid:");
        char *comma_str = strstr(recvBuf,",pwd:");

        if((ssid_str != NULL) && (comma_str != NULL)){
            char ssid[32]={0};
            char pwd[32]={0};

            memcpy(ssid,ssid_str+5,comma_str-(ssid_str+5));
            memcpy(pwd,comma_str+5,recvBuf+strlen(recvBuf)-(comma_str+5));

            printf("==>> {{{%s,%s}}}}\n",ssid,pwd);

            sprintf(sendBuf,"OK ==>%s ++ %d\n",recvBuf,index++);
            ret = sendto(sock_fd, sendBuf, strlen(sendBuf), 0, 
                (struct sockaddr *)&client_addr, sizeof(client_addr));
            if (ret < 0) {
                printf("UDP server send failed!\r\n");
                return -1;
            }
            //保存ssid和密码信息
            saveWifiInfo(ssid,pwd);
            //重启设备
            RebootDevice(3);
        }else{
            //resopese error
            sprintf(sendBuf,"ERROR  \n");
            ret = sendto(sock_fd, sendBuf, strlen(sendBuf), 0, 
                (struct sockaddr *)&client_addr, sizeof(client_addr));
            if (ret < 0) {
                printf("UDP server send failed!\r\n");
                return -1;
            }
        }

        
    }

    return 0;
   
}
 static   char g_ssid[32]={0};
 static   char g_pwd[32]={0};

static int g_listen_fd = 0;
int client_fd = 0;
char recvbuf[512] = {0};

/*任务执行函数，启动TCP服务器端*/
static int tcp_server_task() {
    struct sockaddr_in srv_addr = {0};
    struct sockaddr_in client_addr = {0};
    int ret = 0;
    unsigned int opt = 1;


    // 创建socket
    g_listen_fd = socket(AF_INET,SOCK_STREAM,0);
    if (g_listen_fd == -1) {
        printf("tcp_server_task: create socket failed!\r\n");
        return -1;
    } else {
        printf("tcp_server_task: create socket success!\r\n");
    }

    // 设置socket参数
    ret = setsockopt(g_listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    if (ret == -1) {
        printf("tcp_server_task: set socket option failed!\r\n");
        return -1;
    } else {
        printf("tcp_server_task: set socket option success!\r\n");
    }

    // 绑定端口
    srv_addr.sin_family = AF_INET;
    srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    srv_addr.sin_port = htons(3861);
    ret = bind(g_listen_fd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
    if (ret != 0) {
        printf("tcp_server_task:bind failed, return is %d\r\n", ret);
        closesocket(g_listen_fd);
        g_listen_fd = -1;
        return -1;
    } else {
        printf("tcp_server_task: bind success!\r\n");
    }

    // 监听端口
    ret = listen(g_listen_fd,0);
    if (ret != 0) {
        printf("tcp_server_task:listen failed, return is %d\r\n", ret);
        closesocket(g_listen_fd);
        g_listen_fd = -1;
        return -1;
    } else {
        printf("tcp_server_task: listen success!\r\n");
    }

    // 简单处理，循环处理各客户端连接请求
    while (1)
	{
		int sin_size = sizeof(struct sockaddr_in);
        ret = accept(g_listen_fd,(struct sockaddr *)&client_addr,(socklen_t *)&sin_size);
		if (ret == -1)
		{
			printf("tcp_server_task:accept failed!\r\n");
			continue;
		}
        client_fd = ret;
        printf("tcp_server_task:accept client addr: %s\r\n", inet_ntoa(client_addr.sin_addr));

		//处理目标
		ssize_t ret = 0;
        int count = 0;
		while (1)
		{
            char sendStr[128]={0};
            count++;
            memset_s(recvbuf,sizeof(recvbuf),0,sizeof(recvbuf));
		    // sleep(2);
			if ((ret = recv(client_fd,recvbuf,sizeof(recvbuf),0)) == -1)
			{
				printf("tcp_server_task:recv failed!\r\n");
                break;
			} 
            printf("recvbuf:%s\r\n",recvbuf);
            if(strstr(recvbuf,"music:on") !=NULL)
            {
                buzzerMusicTask(NULL);
                sprintf_s(sendStr,sizeof(sendStr),"OK!\n");
            }else{

                printf("unsupport order!");
                sprintf_s(sendStr,sizeof(sendStr),"unsupport order!\n");

            }

			if ( (ret = send(client_fd,sendStr,strlen(sendStr),0) ) == -1)
			{
				printf("tcp_server_task:send failed!\r\n");
                break;
			} else {
				printf("send :%s\r\n", sendStr);
			}
		}
	}

    closesocket(g_listen_fd);
    g_listen_fd = -1;

    return 0;
}

static BOOL WifiSTATask(void)
{
    WifiConnect(g_ssid, g_pwd);
    tcp_server_task();
     
}
static BOOL WifiAPTask(void)
{

    // 注册wifi事件的回调函数
    g_wifiEventHandler.OnHotspotStaJoin = OnHotspotStaJoinHandler;
    g_wifiEventHandler.OnHotspotStaLeave = OnHotspotStaLeaveHandler;
    g_wifiEventHandler.OnHotspotStateChanged = OnHotspotStateChangedHandler;
    error = RegisterWifiEvent(&g_wifiEventHandler);
    if (error != WIFI_SUCCESS) {
        printf("RegisterWifiEvent failed, error = %d.\r\n", error);
        return -1;
    }
    printf("RegisterWifiEvent succeed!\r\n");
    // 检查热点模式是否使能
    if (IsHotspotActive() == WIFI_HOTSPOT_ACTIVE) {
        printf("Wifi station is  active.\r\n");
        return -1;
    }
    // 设置指定的热点配置
    HotspotConfig config = { 0 };

    strcpy_s(config.ssid, strlen(AP_SSID) + 1, AP_SSID);
    strcpy_s(config.preSharedKey, strlen(AP_PSK) + 1, AP_PSK);
    config.securityType = WIFI_SEC_TYPE_PSK;
    config.band = HOTSPOT_BAND_TYPE_2G;
    config.channelNum = CHANNEL_NUM;

    error = SetHotspotConfig(&config);
    if (error != WIFI_SUCCESS) {
        printf("SetHotspotConfig failed, error = %d.\r\n", error);
        return -1;
    }
    printf("SetHotspotConfig succeed!\r\n");

    // 启动wifi热点模式
    error = EnableHotspot();
    if (error != WIFI_SUCCESS) {
        printf("EnableHotspot failed, error = %d.\r\n", error);
        return -1;
    }
    printf("EnableHotspot succeed!\r\n");

    StartUdpServer();
    return 0;
}

static void OnHotspotStaJoinHandler(StationInfo *info)
{
    if (info == NULL) {
        printf("HotspotStaJoin:info is null.\r\n");
    } else {
        static char macAddress[MAC_ADDRESS_LEN] = { 0 };
        unsigned char *mac = info->macAddress;
        snprintf_s(macAddress, sizeof(macAddress), sizeof(macAddress) - 1, "%02X:%02X:%02X:%02X:%02X:%02X",
            mac[MAC_DATA0], mac[MAC_DATA1], mac[MAC_DATA2], mac[MAC_DATA3], mac[MAC_DATA4], mac[MAC_DATA5]);
        printf("HotspotStaJoin: macAddress=%s, reason=%d.\r\n", macAddress, info->disconnectedReason);
        g_apEnableSuccess++;
    }
}

static void OnHotspotStaLeaveHandler(StationInfo *info)
{
    if (info == NULL) {
        printf("HotspotStaLeave:info is null.\r\n");
    } else {
        static char macAddress[MAC_ADDRESS_LEN] = { 0 };
        unsigned char *mac = info->macAddress;
        snprintf_s(macAddress, sizeof(macAddress), sizeof(macAddress) - 1, "%02X:%02X:%02X:%02X:%02X:%02X",
            mac[MAC_DATA0], mac[MAC_DATA1], mac[MAC_DATA2], mac[MAC_DATA3], mac[MAC_DATA4], mac[MAC_DATA5]);
        printf("HotspotStaLeave: macAddress=%s, reason=%d.\r\n", macAddress, info->disconnectedReason);
        g_apEnableSuccess--;
    }
}

static void OnHotspotStateChangedHandler(int state)
{
    printf("HotspotStateChanged:state is %d.\r\n", state);
    if (state == WIFI_HOTSPOT_ACTIVE) {
        printf("wifi hotspot active.\r\n");
    } else {
        printf("wifi hotspot noactive.\r\n");
    }
}


/** wifi配网案例 */
static void Wifi_Pair_Demo(void)
{
    osThreadAttr_t attr;

    attr.name = "WifiTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = TASK_STACK_SIZE;
    attr.priority = TASK_PRIO;


    int not_found=0;
    
    //从flash读取保存的ssid
    if (UtilsGetValue(KV_SSID, g_ssid, sizeof(g_ssid)-1) < 0) {
        printf("get ssid value failed!\n");
        not_found = 1;
    }
    printf("===== key: %s, value: %s =====\n", KV_SSID, g_ssid);

    //从flash读取保存的密码
    if (UtilsGetValue(KV_PWD, g_pwd, sizeof(g_pwd)-1) < 0) {
        printf("get pwd value failed!\n");
        not_found = 1;
    }
    printf("===== key: %s, value: %s =====\n", KV_PWD, g_pwd);

    printf("==> not_found = %d\n",not_found);
    if(not_found == 1){
        //ssid和密码读取失败,启动ap模式准备配网
        if (osThreadNew((osThreadFunc_t)WifiAPTask, NULL, &attr) == NULL) {
            printf("Failed to create WifiAPTask!\r\n");
        }
    }else{
        //ssid和密码读取成功,启动sta模式连接wifi
        if (osThreadNew((osThreadFunc_t)WifiSTATask, NULL, &attr) == NULL) {
            printf("Failed to create WifiSTATask!\r\n");
        }
        
    }

}

APP_FEATURE_INIT(Wifi_Pair_Demo);
